﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace QuadRemote.Tabs
{
    public class BodeList : List<BodeMeasurement>
    {
        public PointF[] gainGraph;
        public PointF[] phaseGraph;
        public Boolean redraw = true;
        public float maxGain, minGain, maxPhase, minPhase;

        public BodeList()
        {
            this.name = "Live";
        }

        public BodeList(String filename)
        {
            this.filename = filename;
            int slash = filename.LastIndexOf("\\");
            int dot = filename.LastIndexOf(".");
            this.name = filename.Substring(slash + 1, dot - slash - 1);
            string[] lines;
            try
            {
                lines = System.IO.File.ReadAllLines(filename);
                for (int c = 1; c < lines.Length; c++)
                {
                    addLine(lines[c]);
                }

                unwrap();
            }
            catch (Exception e)
            {
                return;
            }
            
        }

        public void insertMeasurement(BodeMeasurement b)
        {
            int index = 0;
            redraw = true;

            while (index < Count)
            {
                if (this[index].freq > b.freq)
                {
                    this.Insert(index, b);
                    this.unwrap();
                    return;
                }
                else if (this[index].freq == b.freq)
                {
                    this.RemoveAt(index);
                    this.Insert(index, b);
                    this.unwrap();
                    return;
                }
                index++;
            }

            this.Add(b);
            this.unwrap();
        }

        public void addLine(String line)
        {
            string[] exp = line.Split(new String[] { ";" }, StringSplitOptions.None);
            BodeMeasurement m = new BodeMeasurement();
            m.freq = float.Parse(exp[0]);
            m.Error_real = float.Parse(exp[1]);
            m.Error_im = float.Parse(exp[2]);
            m.Out_real = float.Parse(exp[3]);
            m.Out_im = float.Parse(exp[4]);
            m.In_real = float.Parse(exp[5]);
            m.In_im = float.Parse(exp[6]);
            m.Signal_real = float.Parse(exp[7]);
            m.Signal_im = float.Parse(exp[8]);
            if (m.Error_real == 0)
            {
                m.hackSetGainPhase(0, float.Parse(exp[9]), float.Parse(exp[10]));
                if (exp.Length > 11)
                {
                    m.hackSetGainPhase(1, float.Parse(exp[11]), float.Parse(exp[12]));
                    m.hackSetGainPhase(2, float.Parse(exp[13]), float.Parse(exp[14]));
                }
            }
            insertMeasurement(m);
        }

        public float getMax(int displayType, float max, float from, float to)
        {
            foreach (BodeMeasurement m in this)
            {
                if (m.freq >= from && m.freq <= to && m.getValue(displayType) > max) max = m.getValue(displayType);
            }
            return max;
        }

        public float getMin(int displayType, float min, float from, float to)
        {
            foreach (BodeMeasurement m in this)
            {
                if (m.freq >= from && m.freq <= to && m.getValue(displayType) < min) min = m.getValue(displayType);
            }
            return min;
        }

        public float getFreqForCross(int displayType, float cross)
        {

            for (int i = 1; i < Count; i++)
            {
                float y1 = this[i-1].getValue(displayType);
                float y2 = this[i].getValue(displayType);

                if ((y1 < cross && y2 >= cross) || (y1 >= cross && y2 < cross))
                {
                    float f1 = this[i - 1].freq;
                    float f2 = this[i].freq;
                    float fd = f2 - f1;

                    y1 -= cross;
                    y2 -= cross;

                    float yrc = (y2 - y1) / fd;

                    return f1 - y1 / yrc;
                }
            }

            return 0.1f;
        }

        public float getValueForFreq(int displayType, float freq)
        {
            for (int i = 1; i < Count; i++)
            {
                float f2 = this[i].freq;

                if (freq <= f2)
                {
                    float f1 = this[i - 1].freq;

                    float dyG = (this[i].getValue(displayType) - this[i - 1].getValue(displayType)) / (f2 - f1);
                    float yyG = this[i - 1].getValue(displayType) - dyG * (this[i - 1].freq - freq);
                    return yyG;
                }
            }

            return 0;
        }

        public void unwrap()
        {
            if (this.Count < 2) return;

            for (int i = 1; i < this.Count; i++)
            {
                this[i].unwrap(this[i - 1]);
            }

            for (int i = 3; i< 6;i++)
            {
                float sum = 0;

                foreach (BodeMeasurement b in this)
                {
                    sum += b.getValue(i);
                }

                sum /= this.Count;

                int inc = 0;
                while (sum > 180)
                {
                    sum -= 360;
                    inc --;
                }
                while (sum < -180)
                {
                    sum += 360;
                    inc ++;
                }

                if (inc != 0)
                {
                    foreach (BodeMeasurement b in this)
                    {
                        b.addPhase(i, inc);
                    }
                }
            }
            redraw = true;
        }

        public void export(String filename)
        {
            String[] lines = new String[1 + Count];
            lines[0] = "Freq;Error_Real;Error_Im;Out_Real;Out_Im;In_Real;In_Im;Signal_Real;Signal_Im;GainOL;PhaseOL;GainCL;PhaseCL;GainPlant;PhasePlant";
            int c = 1;
            foreach (BodeMeasurement m in this)
            {
                lines[c] = m.getLine();
                c++;
            }
            System.IO.File.WriteAllLines(filename, lines);
        }

        public String name;
        public String filename;
    }
}
